<template>
	<view class="page-container">
		<u-tabs :list="tabList" :scrollable="false" @click="tabClick"></u-tabs>
		<template v-if="tabType === 'outputInfo'">
			<view class="text-container">
				<text class="text-title">显示信息</text>
				<view class="text-content">
					<view class="text-content">
						<text>输出电压</text>
						<text>{{ outputInfo.outputVoltage }}V</text>
					</view>
					<view class="text-content">
						<text>输出电流</text>
						<text>{{ outputInfo.outputElectricity }}A</text>
					</view>
				</view>
				<view class="text-content">
					<view class="text-content">
						<text>辅助电压</text>
						<text>{{ outputInfo.auxiliaryVoltage }}V</text>
					</view>
					<view class="text-content"></view>
				</view>
			</view>
			<view class="text-container">
				<text class="text-title">充电桩信息</text>
				<view class="text-content">
					<view class="text-content">
						<text>最小电压</text>
						<text>{{ outputInfo.minVoltage }}V</text>
					</view>
					<view class="text-content">
						<text>最小电流</text>
						<text>{{ outputInfo.minElectricity }}A</text>
					</view>
				</view>
				<view class="text-content">
					<view class="text-content">
						<text>最大电压</text>
						<text>{{ outputInfo.maxVoltage }}V</text>
					</view>
					<view class="text-content">
						<text>最大电流</text>
						<text>{{ outputInfo.maxElectricity }}A</text>
					</view>
				</view>
			</view>
			<view class="text-container">
				<text class="text-title">设置</text>
				<view class="text-content">
					<view class="text-content">
						<text>当前电压</text>
						<text>{{ outputInfo.currentVoltage }}V</text>
					</view>
					<view class="text-content">
						<view class="text-input">
							<u-input class="number-input" border="bottom" type="number" style="padding: 0;"
								placeholder="50~1000" v-model="outputInfo.newcurrentVoltage"
								@blur="blurHandle('newcurrentVoltage', 50, 1000)">
								<text slot="suffix">V</text>
							</u-input>
						</view>
						<view class="text-btn">
							<u-button type="primary" @click="updateHandle('newcurrentVoltage')" text="保存"
								size="small"></u-button>
						</view>
					</view>
				</view>
				<view class="text-content">
					<view class="text-content">
						<text>当前电流</text>
						<text>{{ outputInfo.currentElectricity }}A</text>
					</view>
					<view class="text-content">
						<view class="text-input">
							<!-- <u-input border="bottom" style="padding: 0;" v-model="outputInfo.newcurrentElectricity">
								<text slot="suffix">A</text>
							</u-input> -->
							<u-input class="number-input" border="bottom" type="number" style="padding: 0;"
								placeholder="0~400" v-model="outputInfo.newcurrentElectricity"
								@blur="blurHandle('newcurrentElectricity', 0, 400)">
								<text slot="suffix">A</text>
							</u-input>
						</view>
						<view class="text-btn">
							<u-button type="primary" @click="updateHandle('newcurrentElectricity')" text="保存"
								size="small"></u-button>
						</view>
					</view>
				</view>
				<view class="text-content">
					<view class="text-content">
						<text>接触器</text>
						<text>关闭</text>
					</view>
					<view class="text-content">
						<view class="text-btn">
							<u-button type="primary" text="打开输出" size="small"></u-button>
						</view>
					</view>
				</view>
				<view class="text-content">
					<view class="text-content">
						<text>当前状态</text>
						<text>0</text>
					</view>
					<view class="text-content">

					</view>
				</view>
				<view class="text-content">
					<u-button type="primary" @click="endota" text="结束充电/写数据" size="small"></u-button>
				</view>
			</view>
		</template>
		<template v-if="tabType === 'settingsInfo'">
			<view>
				<view class="text-content">
					<view class="text-content">
						<text>开机输出</text>
						<text>{{ settingsInfo.powerOnOutput ? '开启': '关闭'}}</text>
					</view>
					<view class="text-content">
						<view class="text-btn">
							<u-button type="primary" text="打开" size="small"></u-button>
						</view>
					</view>
				</view>
				<view class="text-content">
					<view class="text-content">
						<text>充满自停</text>
						<text>{{ settingsInfo.fullStop ? '开启': '关闭'}}</text>
					</view>
					<view class="text-content">
						<view class="text-btn">
							<u-button type="primary" text="打开" size="small"></u-button>
						</view>
					</view>
				</view>

				<view class="text-content">
					<view class="text-content">
						<text>关机电流</text>
						<text>{{ settingsInfo.shutdownCurrent }}A</text>
					</view>
					<view class="text-content">
						<view class="text-input">
							<u-input class="number-input" border="bottom" type="number" style="padding: 0;"
								placeholder="0~400" v-model="settingsInfo.newShutdownCurrent"
								@blur="blurHandle('newShutdownCurrent', 0, 400)">
								<text slot="suffix">A</text>
							</u-input>
						</view>
						<view class="text-btn">
							<u-button type="primary" @click="updateHandle('newShutdownCurrent')" text="保存"
								size="small"></u-button>
						</view>
					</view>
				</view>
				<view class="text-content">
					<view class="text-content">
						<text>默认车架号VIN</text>
						<text style="padding: 0;margin: 0 20rpx;">{{ settingsInfo.vin }}</text>
					</view>
				</view>
				<view class="text-content">
					<view class="text-content">
						<text>车架号VIN</text>
						<u-input border="bottom" style="padding: 0;margin: 0 20rpx;" placeholder="17位大写字母和数字"
							v-model="settingsInfo.newVin" @input="inputHandle('newVin', '[^0-9A-Z]')" maxlength="17"
							@blur="blurCheck('newVin', 17)"></u-input>
						<view class="text-btn">
							<u-button type="primary" text="修改" size="small"></u-button>
						</view>
					</view>
				</view>
				<view class="text-content">
					<view class="text-content">
						<text>屏幕开关</text>
						<text>{{ settingsInfo.screenSwitch ? '开启': '关闭'}}</text>
					</view>
					<view class="text-content">
						<view class="text-btn">
							<u-button type="primary" text="打开" size="small"></u-button>
						</view>
					</view>
				</view>
				<view class="text-content">
					<u-button type="primary" @click="beginota" text="更新固件" size="small"></u-button>
				</view>
			</view>
		</template>
		<template v-if="tabType === 'safetyInfo'">
			<view>
				<view class="text-content">
					<view class="text-content">
						<text>蓝牙名称</text>
						<u-input border="bottom" style="padding: 0;margin: 0 20rpx;" placeholder="数字和大小写字母"
							v-model="safetyInfo.deviceName"
							@input="inputHandle('deviceName', '[^0-9a-zA-Z]')"></u-input>
						<view class="text-btn">
							<u-button type="primary" text="修改" size="small"></u-button>
						</view>
					</view>
				</view>
				<view style="padding: 0 20rpx;">
					<u--form labelPosition="top" labelWidth="120" :model="deviceModel" :rules="rules" ref="uForm">
						<u-form-item label="原密码" prop="opassword" borderBottom>
							<u--input type="number" v-model="deviceModel.opassword" border="none"
								maxlength="6"></u--input>
						</u-form-item>
						<u-form-item label="新密码" prop="npassword" borderBottom>
							<u--input type="number" v-model="deviceModel.npassword" border="none"
								maxlength="6"></u--input>
						</u-form-item>
						<u-form-item label="确认密码" prop="spassword" borderBottom>
							<u--input type="number" v-model="deviceModel.spassword" border="none"
								maxlength="6"></u--input>
						</u-form-item>
					</u--form>
				</view>
				<view class="text-content">
					<u-button type="primary" @click="submitDevice()" text="修改密码" size="small"></u-button>
				</view>
			</view>
		</template>

		<u-modal :show="showModal" :showConfirmButton="false">
			<view class="slot-content">
				<text>更新中</text>
				<view>
					{{ currentRate }} / {{ totalRate }}
				</view>
				<view>
					失败数量： {{ errorRate }}
				</view>
				<view>
					发送间隔时间： {{ sendTimes }}
				</view>
				<view>
					发送字节： {{ sendByte }}
				</view>
			</view>
		</u-modal>
	</view>
</template>

<script>
	let _self;
	/* 这三个是需要厂商提供的 服务UUID，特征值UUID*/
	let UUID_SERVICE = '0000FFE0-0000-1000-8000-00805F9B34FB';
	let UUID_CHAR1 = '0000FFE1-0000-1000-8000-00805F9B34FB';
	let UUID_CHAR2 = '0000FFE2-0000-1000-8000-00805F9B34FB';
	let UUID_CHAR3 = '0000FFE3-0000-1000-8000-00805F9B34FB';
	export default {
		data() {
			return {
				mList: [], //搜索到的设备列表
				mDeviceId: 0, //连接的设备
				targetNumber: 'EvCharge_8E44A3E2', //要连接的指定设备
				tabList: [{
						name: '输出',
						type: 'outputInfo'
					},
					{
						name: '设置',
						type: 'settingsInfo'
					},
					{
						name: '安全',
						type: 'safetyInfo'
					},
				],
				tabType: 'outputInfo',
				outputInfo: {
					outputVoltage: '0.00',
					outputElectricity: '0.00',
					auxiliaryVoltage: '0.00',
					minVoltage: '0.00',
					minElectricity: '0.00',
					maxVoltage: '0.00',
					maxElectricity: '0.00',
					currentVoltage: '0.00',
					currentElectricity: '0.00',
					newcurrentVoltage: '',
					newcurrentElectricity: '',
				},
				settingsInfo: {
					powerOnOutput: 0,
					fullStop: 0,
					shutdownCurrent: '0.00',
					newShutdownCurrent: '',
					vin: '',
					newVin: '',
					screenSwitch: ''
				},
				safetyInfo: {
					deviceName: ''
				},
				navbarTitle: '',
				deviceModel: {
					opassword: '',
					npassword: '',
					spassword: ''
				},
				rules: {
					opassword: [{
							type: 'number',
							required: true,
							message: '请填写',
							trigger: ['blur', 'change']
						},
						{
							min: 6,
							max: 6,
							message: '长度为6个字符'
						},
						{
							pattern: /^[0-9]*$/g,
							// 正则检验前先将值转为字符串
							transform(value) {
								return String(value);
							},
							message: '只能包含数字'
						}
					],
					npassword: [{
						type: 'number',
						required: true,
						message: '请填写',
						trigger: ['blur', 'change']
					}, {
						min: 6,
						max: 6,
						message: '长度为6个字符'
					}, {
						pattern: /^[0-9]*$/g,
						// 正则检验前先将值转为字符串
						transform(value) {
							return String(value);
						},
						message: '只能包含数字'
					}],
					spassword: [{
						type: 'number',
						required: true,
						message: '请填写',
						trigger: ['blur', 'change']
					}, {
						min: 6,
						max: 6,
						message: '长度为6个字符'
					}, {
						pattern: /^[0-9]*$/g,
						// 正则检验前先将值转为字符串
						transform(value) {
							return String(value);
						},
						message: '只能包含数字'
					}],
				},

				deviceId: null,
				sevicesList: [],
				serviceUuid: null,
				eigenvalueList: [],
				eigenvalue: null,
				message: "",
				messageHex: "",
				sendMessage: "",

				sendTimes: 200,
				sendByte: 244,

				showModal: false,
				totalRate: 0,
				currentRate: 0,
				errorRate: 0,
			}
		},
		onLoad() {
			_self = this;
			// this.searchDevice() //一旦加载就自动按照蓝牙名称连接
		},
		methods: {
			tabClick(item) {
				this.tabType = item.type
			},
			rightClick() {
				this.beginota()
			},

			inputHandle(str, reg) {
				if (!reg) return;
				const regexp = new RegExp(reg, 'g')
				let value = this[this.tabType][str];
				value = value.replace(regexp, '')
				this.$nextTick(() => {
					this[this.tabType][str] = value || '';
				})
			},

			blurHandle(str, min, max) {
				const num = Number(this[this.tabType][str]);
				if (num >= min && num <= max) {
					this[this.tabType][str] = Math.floor(num).toFixed(2)
				} else {
					uni.$u.toast(`值必须在${min}~${max}之间`)
					this[this.tabType][str] = ''
				}
			},

			blurCheck(str, len) {
				const length = this[this.tabType][str].length;
				if (len !== length) {
					uni.$u.toast(`值必须是${len}位`)
					this[this.tabType][str] = ''
				}
			},

			updateHandle(str) {
				console.warn(str, Number(this[this.tabType][str]))
				const num = Number(this[this.tabType][str])
				// 0 或 NaN
				if (!num) {
					uni.$u.toast(`值不能为空`)
					return;
				}
			},

			submitDevice() {
				console.warn(1231)
				this.$refs.uForm.validate().then(valid => {
					console.warn(1231, valid)
					if (!valid) return;

					// 逻辑
					console.warn(this.deviceModel)
				});
			},

			/* 搜索蓝牙操作 */
			searchDevice() {
				uni.showLoading({
					title: "连接中"
				})
				/* 1、初始化蓝牙 uni.openBluetoothAdapter(OBJECT) */
				uni.openBluetoothAdapter({
						success: (res) => {
							/* 初始化蓝牙成功 */
							/* 2、开始搜索蓝牙设备 uni.startBluetoothDevicesDiscovery(OBJECT */
							uni.startBluetoothDevicesDiscovery({
								allowDuplicatesKey: false, //是否允许同一设备多次上报，但RSSI值会有所不同
								success: (res) => {
									console.log("搜索成功:" + res)
								},
								fail: (res) => {
									console.log("搜索失败:" + res)
								}
							})
						},
						fail: (res) => {
							console.log("初始化蓝牙失败:" + res.code)
							uni.showToast({
								duration: 5000,
								title: "请手动打开手机蓝牙",
								icon: 'none',
							})
						}
					}),
					/* 搜索蓝牙设备回调 */
					uni.onBluetoothDeviceFound(function(CALLBACK) {
						/* 我这边是直接每次遍历指定设备，
						一旦搜索到指定设备就结束搜索，
						 需要显示的就每次都在这边把搜索到的设备添加到数组中，然后界面去显示*/

						/* 搜索过程中如果搜索到需要的设备 */
						CALLBACK.devices.forEach(device => {
							/* 筛选需要的deviceName */
							if (device.name === _self.targetNumber) {
								//找到需要的设备之后，停止搜索
								console.log("搜索到指定设备")
								/* 停止搜索 */
								uni.stopBluetoothDevicesDiscovery({
									success: (res) => {
										uni.getBluetoothDevices({
											success: (devices) => {}
										})
										console.log("停止搜索成功")
									},
									fail: (res) => {
										console.log("停止失败")
										uni.hideLoading();
									}
								})
								/* 执行连接 */
								_self.connectDevice(device.deviceId);
							}
						})
					}),
					/* 监听蓝牙适配器状态变化事件  可以检测当前设备的蓝牙的断开或者连接的情况*/
					uni.onBluetoothAdapterStateChange(function(CALLBACK) {
						//CALLBACK.available 蓝牙适配器是否可用
						//CALLBACK.discovering 蓝牙适配器是否处于搜索状态
						console.log('适配器状态变化', CALLBACK)
					})
			},

			/* 关闭蓝牙适配器*/
			closeBlueAdapter() {
				uni.closeBluetoothAdapter({
					success() {
						console.log("关闭蓝牙适配器成功")
					}
				})
			},
			/* 断开低功耗蓝牙的连接 */
			disconnectBle() {
				uni.closeBLEConnection({
					deviceId: _self.mDeviceId,
					success: (res) => {
						uni.showToast({
							title: "断开成功"
						});
						console.log("断开成功" + res)
					}
				})
			},
			/* 连接低功耗蓝牙 */
			connectDevice(deviceId) {
				console.log("执行到这里了")
				uni.createBLEConnection({
					deviceId, //当前点击的DeviceId

					success: (res) => {
						uni.hideLoading(); //需要先隐藏才行，不然不会显示弹框
						console.log("连接成功")
						//设置MTU，否则传输报文不全，默认是23bytes，但是蓝牙本身是需要3bytes，故而只能传输20bytes,可以了，耶耶耶！！！！
						setTimeout(() => {
							uni.setBLEMTU({
								deviceId,
								mtu: 247,
								success: (res) => {
									console.log('设置MTU最大值成功', res);
								},
								fail: (res) => {
									console.log('设置MTU最大值失败', res);
								}
							});
						}, 1500);
						_self.mDeviceId = deviceId;
						/* 这边获取全部服务，并筛选出当前需要的*/
						_self.getBLEDeviceServices(deviceId)

					},
					fail: (error) => {
						/* 连接失败 */
						uni.hideLoading();
						console.log("连接失败")
						console.log(error);
					}
				})
				/* 监听蓝牙设备的连接状态 */
				uni.onBLEConnectionStateChange(function(CALLBACK) {
					console.log(CALLBACK.deviceId + "连接状态:" + CALLBACK.connected)
				})
			},
			/* 获取所有的服务(目前理解来说应该是进入服务) */
			getBLEDeviceServices(deviceId) {
				console.log("开始获取服务")
				//连接成功之后需要延时，继续操作才不会出问题,延时时间短一点都没关系，我这边用了1秒
				setTimeout(() => {
					uni.getBLEDeviceServices({
						// 这里的 deviceId 需要已经通过 createBLEConnection 与对应设备建立链接
						deviceId,
						success: (res) => {
							console.log('device services:', res)
							res.services.forEach((item) => {
								let serviceId = item.uuid;
								if (serviceId == UUID_SERVICE) {
									console.log('serverId:', serviceId)
									/* 进入特征值 */
									_self.getBLEDeviceCharacteristics(deviceId, serviceId);
								}
							})
						},
						fail: (error) => {
							console.log("获取服务失败")
							console.log(error)
							uni.hideLoading();
						}
					})
				}, 2000)
			},
			/* 获取所有特征值 */
			getBLEDeviceCharacteristics(deviceId, serviceId) {
				console.log("开始获取特征")
				setTimeout(() => {
					uni.getBLEDeviceCharacteristics({
						// 这里的 deviceId 需要已经通过 createBLEConnection 与对应设备建立链接
						deviceId,
						// 这里的 serviceId 需要在 getBLEDeviceServices 接口中获取
						serviceId,
						success: (res) => {
							console.log(res)
							//let characteristics = res.characteristics
							res.characteristics.forEach((item) => {
								let characterId = item.uuid;
								/* 只要用到的唤醒即可 */
								if (characterId == UUID_CHAR1) {
									console.log('characteristicId:', characterId)
									_self.notifyBLECharacteristicValueChange(deviceId,
										serviceId, characterId)
								}
							})
						},
						fail: (res) => {
							uni.hideLoading();
							console.log(res)
						}
					})
				}, 1000)
			},
			notifyBLECharacteristicValueChange(deviceId, serviceId, characteristicId) {
				console.log("开始唤醒")
				uni.notifyBLECharacteristicValueChange({
					state: true, // 启用 notify 功能
					// 这里的 deviceId 需要已经通过 createBLEConnection 与对应设备建立链接
					deviceId,
					// 这里的 serviceId 需要在 getBLEDeviceServices 接口中获取
					serviceId,
					// 这里的 characteristicId 需要在 getBLEDeviceCharacteristics 接口中获取
					characteristicId,
					success: (res) => {
						uni.hideLoading();
						//_self.meter.tunnel = _self.setTokenTest;
						/* 连接成功 */
						uni.showToast({
							duration: 3000,
							title: "连接成功",
							icon: 'success'
						});
						console.log('开启监听成功', res.errMsg)
						_self.listenValueChange() // 这里直接就去监听ESP32发过来的数据了
					},
					fail: (res) => {
						uni.hideLoading();
						console.log('开启监听失败', res.errMsg)
					}
				})
			},

			/* 数据格式的转换工具类 */
			/* 字符串转arraybuffer */
			string2buffer: function(str) {
				// 首先将字符串转为16进制
				let val = str
				/* for (let i = 0; i < str.length; i++) {
					if (val === '') {
						val = str.charCodeAt(i).toString(16)
					} else {
						val += ',' + str.charCodeAt(i).toString(16)
					}
				} */
				console.log(val)
				// 将16进制转化为A rrayBuffer
				return new Uint8Array(val.match(/[\da-f]{2}/gi).map(function(h) {
					return parseInt(h, 16)
				})).buffer
			},

			ab2hex(buffer) {
				const hexArr = Array.prototype.map.call(
					new Uint8Array(buffer),
					function(bit) {
						return ('00' + bit.toString(16)).slice(-2)
					}
				)
				return hexArr.join('')
			},
			// 将16进制的内容转成我们看得懂的字符串内容
			hexCharCodeToStr(hexCharCodeStr) {
				var trimedStr = hexCharCodeStr.trim(); // 移除字符串的两端空格以及其他类型的空白字符
				var rawStr = trimedStr.substr(0, 2).toLowerCase() === "0x" ? trimedStr.substr(2) :
					trimedStr; //前边如果是0x就从第3个开始截取
				var len = rawStr.length;
				if (len % 2 !== 0) { // 长度对2取余如果不是0就是不正确
					alert("存在非法字符!");
					return "";
				}
				var curCharCode;
				var resultStr = [];
				for (var i = 0; i < len; i = i + 2) { // 每2个数据计算一次
					curCharCode = parseInt(rawStr.substr(i, 2), 16); // 每两个数字转成16进制
					resultStr.push(String.fromCharCode(curCharCode)); // 将所有16进制数字组合在一起
				}
				return resultStr.join("");
			},

			/* arraybuffer 转字符串 */
			bufferString: function(str) {
				// ArrayBuffer转16进度字符串示例
				function ab2hex(buffer) {
					const hexArr = Array.prototype.map.call(
						new Uint8Array(buffer),
						function(bit) {
							return ('00' + bit.toString(16)).slice(-2)
						}
					)
					return hexArr.join('')
				}
				//16进制
				let systemStr = ab2hex(str)
				// console.log(hexCharCodeToStr(systemStr),99)
				function hexCharCodeToStr(hexCharCodeStr) {
					var trimedStr = hexCharCodeStr.trim();
					var rawStr = trimedStr.substr(0, 2).toLowerCase() === "0x" ? trimedStr.substr(2) : trimedStr;
					var len = rawStr.length;
					if (len % 2 !== 0) {
						alert("Illegal Format ASCII Code!");
						return "";
					}
					var curCharCode;
					var resultStr = [];
					for (var i = 0; i < len; i = i + 2) {
						curCharCode = parseInt(rawStr.substr(i, 2), 16); // ASCII Code Value
						let str5 = String.fromCharCode(curCharCode)
						if (str5.startsWith('\n') == false) {
							resultStr.push(String.fromCharCode(curCharCode));
						}
					}
					return resultStr.join("");

				}
				// console.log(hexCharCodeToStr(systemStr),888)
				return hexCharCodeToStr(systemStr)

			},
			/* 蓝牙通信工具 */
			getError(errorCode) {
				if (errorCode == 0) return "OK";
				if (errorCode == 10000) return "未初始化蓝牙适配器";
				if (errorCode == 10001) return "当前蓝牙适配器不可用";
				if (errorCode == 10002) return "没有找到指定设备";
				if (errorCode == 10003) return "连接失败";
				if (errorCode == 10004) return "没有找到指定服务";
				if (errorCode == 10005) return "没有找到指定特征值";
				if (errorCode == 10006) return "当前连接已断开";
				if (errorCode == 10007) return "当前特征值不支持此操作";
				if (errorCode == 10008) return "其余所有系统上报的异常";
				if (errorCode == 10009) return "Android 系统特有，系统版本低于 4.3 不支持 BLE";
				return "未知异常";
			},
			/* 异步执行，延时函数 */
			delayed(ms, res) {
				return new Promise((resolve, reject) => {
					setTimeout(function() {
						resolve(res);
					}, ms)
				});
			},

			listenValueChange() {
				let that = this
				/* 这边对特征值1进行数据的监听  */
				uni.onBLECharacteristicValueChange(function(CALLBACK) {
					let result = that.ab2hex(CALLBACK.value);
					console.log("接收到的", result)

					//所有数据处理在这里
					_self.outputInfo.currentVoltage = parseInt(result.slice(44, 48), 16) / 10;
					_self.outputInfo.currentElectricity = parseInt(result.slice(48, 52), 16) / 10;
					console.log("接收到的", _self.outputInfo.currentVoltage)

					_self.message = that.hexCharCodeToStr(result); //这里已经把所有数据转成字符串了
					_self.message = String(_self.message);
					_self.settingsInfo.vin = _self.message.slice(4, 21); //从 start下标 开始，保留到 end下标 的前一个结束
					_self.settingsInfo.vin = _self.settingsInfo.vin.toUpperCase();
					console.log("接收到的", _self.settingsInfo.vin)
				})
			},

			//读取数据
			read() {
				let that = this
				uni.readBLECharacteristicValue({
					deviceId: that.deviceId,
					serviceId: that.serviceUuid,
					characteristicId: that.eigenvalue,
					success(res) {
						console.log(res, "数据读取成功")
						uni.showToast({
							title: 'read指令发送成功'
						})
					},
					fail(err) {
						console.error(err)
						uni.showToast({
							title: 'read指令发送失败',
							icon: 'error'
						})
					}
				})
			},
			//发送内容的输入框
			clearIptC() {
				this.sendMessage = ""
			},
			/* 连接成功以后，执行设置的操作，并且打开返回值的监听开关并监听 */
			beginota() {
				let that = this
				/* 获取所有的服务 */
				/* 每次设置前都将notify打开（设备回复开关） */
				let tokenArr = '11';
				let arrayBuffer = that.string2buffer(tokenArr)
				console.log(arrayBuffer)
				/* 当长度不满20的时候执行最后一次发送即可 */
				uni.writeBLECharacteristicValue({
					deviceId: _self.mDeviceId,
					serviceId: UUID_SERVICE,
					characteristicId: UUID_CHAR2,
					value: arrayBuffer,
					success: (res) => {
						/* 发送成功 */
						console.log('开始OTA成功', res)
					},
					fail: (error) => {
						/* 发送失败 */
						console.log('开始OTA失败', error)
					}
				})
				that.dataota()
			},
			dataota() {
				let that = this
				uni.showLoading({
					title: '正在下载中'
				})
				uni.request({
					url: 'http://s7qtpg1wb.hd-bkt.clouddn.com/FD_EVCHARGER.bin',
					responseType: 'arraybuffer',
				}).then(res => {
					that.printbuffs(res.data)
				}).catch(err => {
					console.warn(err)
					uni.hideLoading()
				})
			},
			//指令发送分包处理
			async printbuffs(buffer) {
				// 1.并行调用多次会存在写失败的可能性
				// 2.建议每次写入不超过20字节
				// 分包处理，延时调用
				let that = this;
				if (!that.sendByte || !that.sendTimes) {
					that.showModal = false
					uni.showModal({
						content: '间隔时间或字节数不能为空',
						showCancel: false
					})
					return
				}
				that.errorRate = 0; // 错误的数量
				that.currentRate = 0; // 
				const offset = that.sendByte; // 偏移量
				this.totalRate = Math.ceil(buffer.byteLength / offset) // 总包数，ceil是取整的意思

				uni.hideLoading()
				this.showModal = true

				let pos = 0; // 位置
				let bytes = buffer.byteLength; // 总字节
				while (bytes > 0) {
					let endPos = bytes > offset ? (pos + offset) : (pos + bytes); // endPos是发送的一个片段的最终的一个字节的位置
					const tempBuffer = buffer.slice(pos, endPos); //tempBuffer是这个片段的一个临时buffer，
					pos += offset; //pos是每个片段的起始位置，每次增加一个偏移量
					bytes -= offset; //总字节减去一个偏移量
					if (that.errorRate >= 1) { //如果有一个错误都会更新失败
						that.showModal = false
						uni.showModal({
							content: '更新失败',
							showCancel: false
						})
						break;
						return
					}
					// 延迟发送，按照设置时间，到时间后发送buffer里面的内容，注意看，这个里面并没有用到sendStr，而是直接用的send(buffer)	
					// (buffer => {that.send(buffe  r)})是箭头函数，前边的buffer是参数，后边的花括号里面的是函数的执行语句，通常是一条或多条语句，也可以是一个表达式		
					await that.sendDelay(that.sendTimes, tempBuffer).then(buffer => {
						that.send(buffer)
					})
					//结束OTA
					if (0 >= bytes) {
						that.endota()
					}
				}
			},
			// 延时函数
			sendDelay(delay, buffer) {
				return new Promise((resolve, reject) => {
					setTimeout(() => resolve(buffer), delay);
				})
			},
			sendStr() {
				//  向蓝牙设备发送一个0x00的16进制数据，这个只是操作"发送数据"那里会用到这个,.charCodeAt()
				let msg = this.sendMessage
				console.log(msg, '$$$$$$$$$$$$$$$$$$$$$$$$$$');


				const buffer = new ArrayBuffer(msg.length)
				const dataView = new DataView(buffer)
				dataView.setUint8(0, 0)

				for (var i = 0; i < msg.length; i++) {
					dataView.setUint8(i, msg.charAt(i))
				}
				this.send(buffer)
			},

			//发送数据
			send(buffer) {
				const that = this
				uni.writeBLECharacteristicValue({
					deviceId: _self.mDeviceId,
					serviceId: UUID_SERVICE,
					characteristicId: UUID_CHAR3,
					value: buffer,
					success(res) {
						that.currentRate++;
						// uni.showLoading({
						// 	title: `更新中${that.currentRate}/${that.totalRate}`,
						// })
						if (that.currentRate >= that.totalRate) {
							// uni.hideLoading()
							that.showModal = false
							uni.showModal({
								content: '更新成功',
								showCancel: false
							})
						}
						// console.log('writeBLECharacteristicValue success', res.errMsg)
					},
					fail(err) {
						that.errorRate++
						console.log('writeBLECharacteristicValue error', err)
						// that.showModal = false
						// uni.showModal({
						// 	content: '更新失败',
						// 	showCancel: false
						// })
					}
				})
			},
			endota() {
				let that = this
				/* 获取所有的服务 */
				/* 每次设置前都将notify打开（设备回复开关） */
				let tokenArr = '13';
				let arrayBuffer = that.string2buffer(tokenArr)
				console.log(arrayBuffer)
				setTimeout(() => {
					uni.writeBLECharacteristicValue({
						deviceId: _self.mDeviceId,
						serviceId: UUID_SERVICE,
						characteristicId: UUID_CHAR2,
						value: arrayBuffer,
						success: (res) => {
							/* 发送成功 */
							console.log('结束OTA成功', res)
						},
						fail: (error) => {
							/* 发送失败 */
							console.log('结束OTA失败', error)
						}
					})
				}, 300);
			},
			/* 连接成功以后，执行设置的操作 */
			writeMeter() {
				let that = this
				/* 获取所有的服务  _self.outputInfo.newcurrentVoltage*/
				/* 每次设置前都将notify打开（设备回复开关）*/
				let tokenArr = 'ef000000060a512233191974345957215cdd3a16';
				let arrayBuffer = that.string2buffer(tokenArr)
				console.log(arrayBuffer)
				/* 测试发现如果不做分包发送的话，还是会有问题，所以这边还是需要做分包发送 */
				that.writeDevice(arrayBuffer);
			},
			/* 执行演示分包操作 */
			writeDevice(_Buffer) {
				let that = this
				let Num = 0;
				let ByteLength = _Buffer.byteLength;
				let i = 1;
				while (ByteLength > 0) {
					i++;
					let TmpBuffer;
					console.log("TmpBuffer", TmpBuffer)
					console.log("Num", Num)
					console.log("ByteLength", ByteLength)
					console.log('执行最后一次')
					TmpBuffer = _Buffer.slice(Num, Num + ByteLength)
					Num += ByteLength
					ByteLength -= ByteLength
					/* 当长度不满20的时候执行最后一次发送即可 */
					that.delayed(500).then(() => {
						uni.writeBLECharacteristicValue({
							deviceId: _self.mDeviceId,
							serviceId: UUID_SERVICE,
							characteristicId: UUID_CHAR2,
							value: TmpBuffer,
							success: (res) => {
								/* 发送成功 */
								console.log('发送成功', res)
							},
							fail: (error) => {
								/* 发送失败 */
								console.log('发送失败', error)
							}
						})
					})
				}
			},

		},
	}
</script>

<style scoped>
	.page-container {
		padding-top: 10rpx;
	}

	.text-container {
		padding: 10rpx;
	}

	.text-title {
		font-size: 32rpx;
		font-weight: 500;
	}

	.text-input {
		height: 60rpx;
		width: 160rpx;
		line-height: 60rpx;
	}

	.text-content {
		display: flex;
		justify-content: space-between;
		flex: 1;
		padding: 0px 10px;
		line-height: 40px;
	}

	.text-btn {
		padding-top: 10rpx;
	}

	.box {
		width: 100%;
		height: 500rpx;
		box-sizing: border-box;
		margin-bottom: 8rpx;
		border: 1px solid rgb(138, 145, 159);
	}

	.item {
		box-sizing: border-box;
		padding: 10rpx;
		border-bottom: 1px solid gray;
	}

	/* button {
		margin-bottom: 20rpx;
	} */

	.btnBox {
		display: flex;
		display: flex;
		align-items: flex-end;
		flex-wrap: wrap;
	}

	.BuuetoothServiceList {
		width: 100%;
		height: 2rem;
		margin-bottom: 8rpx;
		line-height: 2rem;
		text-align: center;
		font-weight: 700;

	}

	.msg_x {
		border: 2px solid seagreen;
		width: 98%;
		margin: 10rpx auto;
		box-sizing: border-box;
		padding: 20rpx;
	}

	/*	​.msg_txt {
		margin-bottom: 20rpx;
	} */

	.clearInput {
		width: 5%;
		height: 3rem;
		line-height: 3rem;
		float: left;
		margin-left: 2%;
	}
</style>